#!/usr/bin/env python
# -*- coding: utf-8 -*-

from typing import Any

from cta.interface.action.update_quant2_account.abstract_update_quant2_account_action import \
    AbstractUpdateQuant2AccountAction
from web.constants.datetime_format import DatetimeFormat
from web.constants.direction import Direction
from web.domain.responsibility_chain_dto import ResponsibilityChainDto
from web.manager.log_manager import LogManager
from web.models import CommodityFutureInfo
from web.models.commodity_future_date_contract_data import CommodityFutureDateContractData
from web.models.quant2_account import Quant2Account
from web.models.quant2_commodity_future_transaction_record import Quant2CommodityFutureTransactionRecord
from web.util.commodity_future_code_util import CommodityFutureCodeUtil
from web.util.datetime_util import DatetimeUtil
from web.util.fee_util import FeeUtil

Logger = LogManager.get_logger(__name__)

class UpdateQuant2AccountAfterOpenPosition(AbstractUpdateQuant2AccountAction):
    """
    普通的开仓后更新quant2_account表动作
    """

    def exec(self, responsibility_chain_dto: ResponsibilityChainDto = None) -> Any:
        Logger.info("开仓后更新quant2_account表")

        transaction_date: str = responsibility_chain_dto.transaction_date

        # 返回量化账户
        quant2_account_list: list[Quant2Account] = self.quant2_account_dao.find_all()

        for quant2_account in quant2_account_list:
            # 期货资产
            commodity_future_assets: float = 0.0
            # 当天买入的期货资产
            current_open_commodity_future_assets: float = 0.0
            # 买入期货品种的数量
            sell_or_buy_commodity_future_number: int = 0

            # 计算每一个量化账户，在某一天开仓后的收益
            quant2_commodity_future_transaction_record_list: list[Quant2CommodityFutureTransactionRecord] = self.quant2_commodity_future_transaction_record_dao.find_by_account_name_and_not_close_position(quant2_account.account_name)

            # 如果没有开仓期货，则直接将quant2_account表中的记录插入到quant2_account_log表中
            if quant2_commodity_future_transaction_record_list is None or len(quant2_commodity_future_transaction_record_list) == 0:
                continue

            for quant2_commodity_future_transaction_record in quant2_commodity_future_transaction_record_list:
                # 查找某个期货在某一天的收盘价
                # 期货的收盘价
                commodity_future_date_contract_data: CommodityFutureDateContractData = self.commodity_future_date_contract_data_dao.find_by_code_and_transaction_date(quant2_commodity_future_transaction_record.code, transaction_date)

                if commodity_future_date_contract_data is None:
                    # 说明期货在这一天没有交易记录
                    Logger.warning("期货[%s]在日期[%s]没有交易记录，开始查找前一个交易日的记录", quant2_commodity_future_transaction_record.code, transaction_date)

                    # 如果在某一天没有收盘价，则查找最近一个交易日的收盘价
                    commodity_future_date_contract_data = self.commodity_future_date_contract_data_dao.find_last_commodity_future_date_contract_data_by_code_and_date(quant2_commodity_future_transaction_record.code, transaction_date)

                # 查询commodity_future_info记录（大小写不敏感的精确匹配查询）
                filter_dict = {'code__iexact': CommodityFutureCodeUtil.code_to_contract_code(commodity_future_date_contract_data.code)}
                commodity_future_info: CommodityFutureInfo = self.commodity_future_info_dao.find_one(filter_dict,dict(), list())

                # 开仓期货后，正在持有的期货资产、持有期货的数量
                if quant2_commodity_future_transaction_record.direction == Direction.Up:
                    commodity_future_assets = commodity_future_assets + FeeUtil.calculate_open_commodity_future_cost(quant2_commodity_future_transaction_record.buy_price, commodity_future_info, quant2_commodity_future_transaction_record.buy_lot) \
                                                   + FeeUtil.calculate_actual_profit_and_loss(quant2_commodity_future_transaction_record.direction, quant2_commodity_future_transaction_record.buy_price, commodity_future_date_contract_data.close_price, commodity_future_info.transaction_multiplier, quant2_commodity_future_transaction_record.buy_lot)
                    sell_or_buy_commodity_future_number = sell_or_buy_commodity_future_number + 1
                if quant2_commodity_future_transaction_record.direction == Direction.Down:
                    commodity_future_assets = commodity_future_assets + FeeUtil.calculate_open_commodity_future_cost(quant2_commodity_future_transaction_record.sell_price, commodity_future_info, quant2_commodity_future_transaction_record.sell_lot) \
                                                    + FeeUtil.calculate_actual_profit_and_loss(quant2_commodity_future_transaction_record.direction, quant2_commodity_future_transaction_record.sell_price, commodity_future_date_contract_data.close_price, commodity_future_info.transaction_multiplier, quant2_commodity_future_transaction_record.sell_lot)
                    sell_or_buy_commodity_future_number = sell_or_buy_commodity_future_number + 1

                # 计算当天开仓的期货资产
                if (quant2_commodity_future_transaction_record.direction == Direction.Up and quant2_commodity_future_transaction_record.buy_date == DatetimeUtil.str_to_datetime(transaction_date, DatetimeFormat.Date_Format)) or \
                    (quant2_commodity_future_transaction_record.direction == Direction.Down and quant2_commodity_future_transaction_record.sell_date == DatetimeUtil.str_to_datetime(transaction_date, DatetimeFormat.Date_Format)):
                    if quant2_commodity_future_transaction_record.direction == Direction.Up:
                        current_open_commodity_future_assets = current_open_commodity_future_assets + float(FeeUtil.calculate_open_commodity_future_cost(commodity_future_date_contract_data.close_price, commodity_future_info, quant2_commodity_future_transaction_record.buy_lot))
                    if quant2_commodity_future_transaction_record.direction == Direction.Down:
                        current_open_commodity_future_assets = current_open_commodity_future_assets + float(FeeUtil.calculate_open_commodity_future_cost(commodity_future_date_contract_data.close_price, commodity_future_info, quant2_commodity_future_transaction_record.sell_lot))

            # 更新quant2_account表
            current_open_position_commission: float = self.quant2_commodity_future_transaction_record_dao.sum_open_commission_by_account_name_and_date(quant2_account.account_name, transaction_date)
            # total_close_commission: float = self.quant2_commodity_future_transaction_record_dao.sum_close_commission_by_account_name(quant2_account.account_name)
            self.quant2_account_dao.update_after_open_position(sell_or_buy_commodity_future_number, commodity_future_assets,
                                                               current_open_position_commission, current_open_commodity_future_assets, quant2_account.account_name)

        super().next(responsibility_chain_dto)